import { useCallback, useEffect, useMemo, useState } from 'react';
import { fetchBasket, saveBasket, type BasketItem, type BasketResponse } from '../lib/api';
import { useAuth } from './useAuth';

export interface CartState {
  items: BasketItem[];
  total: number;
  loading: boolean;
  error: string | null;
  refresh: () => Promise<void>;
  updateQuantity: (productId: string, quantity: number) => Promise<void>;
  removeItem: (productId: string) => Promise<void>;
  clear: () => Promise<void>;
  addItem: (item: { productId: string; productName: string; unitPrice: number; quantity?: number }) => Promise<void>;
}

export const useCart = (): CartState => {
  const { isAuthenticated } = useAuth();
  const [basket, setBasket] = useState<BasketResponse | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const refresh = useCallback(async () => {
    if (!isAuthenticated) {
      setBasket(null);
      return;
    }

    setLoading(true);
    setError(null);
    try {
      const response = await fetchBasket();
      setBasket(response);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to load basket');
    } finally {
      setLoading(false);
    }
  }, [isAuthenticated]);

  useEffect(() => {
    void refresh();
  }, [refresh]);

  const persistChanges = useCallback(
    async (items: BasketItem[]) => {
      if (!isAuthenticated) {
        return;
      }

      const updated = await saveBasket(items);
      setBasket(updated);
    },
    [isAuthenticated],
  );

  const updateQuantity = useCallback(
    async (productId: string, quantity: number) => {
      if (!basket) return;
      const sanitized = quantity <= 0 ? 1 : quantity;
      const updatedItems = basket.items.map((item) =>
        item.productId === productId ? { ...item, quantity: sanitized } : item,
      );
      await persistChanges(updatedItems);
    },
    [basket, persistChanges],
  );

  const removeItem = useCallback(
    async (productId: string) => {
      if (!basket) return;
      const updatedItems = basket.items.filter((item) => item.productId !== productId);
      await persistChanges(updatedItems);
    },
    [basket, persistChanges],
  );

  const clear = useCallback(async () => {
    await persistChanges([]);
  }, [persistChanges]);

  const addItem = useCallback(
    async (item: { productId: string; productName: string; unitPrice: number; quantity?: number }) => {
      if (!basket) {
        const newItem: BasketItem = {
          productId: item.productId,
          productName: item.productName,
          unitPrice: item.unitPrice,
          quantity: item.quantity ?? 1,
        };
        await persistChanges([newItem]);
        return;
      }

      const existing = basket.items.find((x) => x.productId === item.productId);
      let updatedItems: BasketItem[];
      if (existing) {
        updatedItems = basket.items.map((x) =>
          x.productId === item.productId
            ? { ...x, quantity: x.quantity + (item.quantity ?? 1) }
            : x,
        );
      } else {
        updatedItems = [
          ...basket.items,
          {
            productId: item.productId,
            productName: item.productName,
            unitPrice: item.unitPrice,
            quantity: item.quantity ?? 1,
          },
        ];
      }

      await persistChanges(updatedItems);
    },
    [basket, persistChanges],
  );

  const derived = useMemo(() => {
    if (!basket) {
      return { items: [], total: 0 };
    }

    const total = basket.items.reduce(
      (sum, item) => sum + item.unitPrice * item.quantity,
      0,
    );
    return { items: basket.items, total };
  }, [basket]);

  return {
    items: derived.items,
    total: derived.total,
    loading,
    error,
    refresh,
    updateQuantity,
    removeItem,
    clear,
    addItem,
  };
};
